home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
t3_1
/
doc.lha
/
documentation
/
manual
/
state.mss
< prev
next >
Wrap
Text File
|
1987-06-30
|
11KB
|
313 lines
@part[STATE, root "TMAN.MSS"] @Comment{-*-System:TMAN-*-}
@chap[Side effects]
A @iixs[side-effect] is a change in the @ix[state] of a running @tau[]
system, such as a change in the value stored in some location, or an
effect on the outside world.
@index[Locations]
Many useful programs can be written which make no use of side-effects.
In principle, side-effects other than those controlling the outside world are
unnecessary. However, side effects, when used carefully, can be used to
promote program modularity and readability. In addition, they may be
necessary in a @Tau[] implementation to obtain efficient program
execution.
@section[Assignment]
@label[Assignmentsection] @Comment{ref: number chapter, list chapter}
@tau[] provides several special forms which perform assignment to
@i[locations]. A location is a place in which a value may be stored,
for example, a variable, or the car of a list, or a component of a
structure. Locations are not objects @i[per se], although
references to them may be obtained through the use of @termi[locatives].
@dc{ Talk about the syntax of @i[location] in the following. }
@AnEquivE(Tfn="SET",Efn="SETQ")
@AnEquivE(Tfn="SET",Efn=":=")
@info[NOTES="Special form",EQUIV="SETF"]
@desc[(SET @i[location new-value]) @yl[] @i[new-value]]
@tc[SET] is a generalized assignment operator.
It alters the location specified by @i[location] to hold @i[new-value].
The value of any @tc[SET]-expression is the @i[new-value] thus stored.
If @i[location] is a symbol, then it names a variable which has been
previously bound by a @tc[LAMBDA] or an @tc[LSET] (or indirectly by
any form which does @tc[LAMBDA]-binding, such as @tc[LET]),
whose value is to be altered.
@begin[ProgramExample]
(SET X (LIST 1 2 3)) @ev[] (1 2 3)
X @ev[] (1 2 3)
@end[ProgramExample]
@i[Location] may also have the syntax of a call to an @i[access-type]
procedure or operation such as @tc[CAR]. (In this manual, these are
marked as @i[Settable].)
@label[Settable] @Comment{ref: operations chapter}
@begin[ProgramExample, LongLines keep]
(SET (CAR X) 'A) @ev[] A
X @ev[] (A 2 3)
(SET (@i[proc arg@-[1]] ... @i[arg@-[n]]) @i[value]) @~
@ce[] ((SETTER @i[proc]) @i[arg@-[1]] ... @i[arg@-[n] value])
@end[ProgramExample]
@EndDesc[SET]
@info[NOTES="Operation"]
@desc[(SETTER @i[procedure]) @yl[] @i[procedure]]
Given an access routine, @tc[SETTER] returns a corresponding alteration
routine. @wt[(SETTER CAR)], for example, evaluates to a primitive
procedure that takes two arguments, a list whose car is to be changed,
and a value to store in the car of the list.
See also @tc[DEFINE-SETTABLE-OPERATION], page
@pageref[DEFINE-SETTABLE-OPERATION]. @dc{ ? }
@EndDesc[SETTER]
@info[NOTES="Special form"]
@desc[(SWAP @i[location new-value]) @yl[] @i[object]]
This behaves the same as @tc[SET], except that the value
returned is the old value found in @i[location],
rather than the @i[new-value]. For example,
the following expression exchanges the values of the variables @tc[X] and
@tc[Y]:
@begin[ProgramExample]
(SET X (SWAP Y X))
@end[ProgramExample]
@EndDesc[SWAP]
@info[NOTES="Special form"]
@desc[(EXCHANGE @i[location1 location2]) @yl[] @i[undefined]]
Exchanges the values in the two locations.
@dc{Explain more fully.}
@EndDesc[EXCHANGE]
@info[NOTES="Special form"]
@desc[(MODIFY @i[location procedure]) @yl[] @i[object]]
Stores a value in the @i[location] which is obtained by applying @i[procedure]
to the old value in @i[location].
@begin[ProgramExample]
(MODIFY @i[location] 1+) @ce[] (INCREMENT @i[location])
@end[ProgramExample]
@enddesc[MODIFY]
@info[NOTES="Special form"]
@desc[(MODIFY-LOCATION @i[location continuation]) @yl[] @i[object]]
Calls @i[continuation], which should be a procedure of two arguments,
passing it an access procedure
of no arguments, which fetches the value in @i[location];
and an update procedure of one argument, which will store a
new value in @i[location].
@dc{bletch}
@tc[MODIFY-LOCATION]'s purpose is to ensure that any subforms
of the form for @i[location] are evaluated only once. For example,
@begin[ProgramExample]
(INCREMENT (CAR (HACK))
@ce[]
(MODIFY-LOCATION (CAR (HACK))
(LAMBDA (FETCH STORE) (STORE (+ (FETCH) 1))))
@end[ProgramExample]
In this expression, @tc[(HACK)] will be evaluated only once, whereas in the following
naive expansion
@begin[ProgramExample]
(SET (CAR (HACK)) (+ (CAR (HACK)) 1))
@end[ProgramExample]
it is evaluated twice, which is presumably neither necessary nor desirable.
The expansion of @tc[MODIFY-LOCATION] forms introduces extra temporary
variables, as needed, to account for this.
Although awkward when written directly,
@tc[MODIFY-LOCATION] is useful in macro expansions.
@tc[MODIFY-LOCATION] is the common special form in terms of which other
@qu[modification] forms such as @tc[PUSH], @tc[MODIFY], and @tc[SWAP]
are implementeded as macros.
For example, one might define a @tc[DOUBLE] macro, which multiplies by two the
value in a location, as follows:
@begin[ProgramExample]
(DEFINE-SYNTAX (DOUBLE FORM)
`(MODIFY-LOCATION
,FORM
(LAMBDA (FETCH STORE) (STORE (* (FETCH) 2)))))
(DOUBLE (CAR (HACK)))
@end[ProgramExample]
@EndDesc[MODIFY-LOCATION]
@section[Locatives]
@label[locatives section] @Comment{ref: environments chapter.}
@i[Locatives] in @tau[] are similar to the @i[pointers] or
@i[references] of languages like C or Algol 68.
Locatives are obtained by evaluating @tc[LOCATIVE]-expressions. The
value in the location they refer to may be fetched using the
@tc[CONTENTS] operation, and stored using @tc[SET].
Objects which act as locatives may be created using @tc[OBJECT], as long
as they handle the @tc[CONTENTS] and @tc[(SETTER CONTENTS)] operations
appropriately, and handle @tc[LOCATIVE?] by returning true.
@AnEquivE[Tfn="LOCATIVE",Efn="LOCF"]
@info[NOTES="Special form"]
@desc[(LOCATIVE @i[location]) @yl[] @i[locative]]
Returns a locative which accesses the location specified by @i[location].
@i[Location] receives similar treatment to the @i[location] position
in the @tc[SET] special form; it may refer to a variable, or to a
@qu"field" within some mutable structure, for example the car of a pair.
The following equivalence approximates the behavior of @tc[LOCATIVE]:
@begin[ProgramExample]
(LOCATIVE @i[location])
@ce[]
(OBJECT NIL
((CONTENTS SELF) @i[location])
(((SETTER CONTENTS) SELF VALUE) (SET @i[location] VALUE))
((LOCATIVE? SELF) T))
@end[ProgramExample]
This is accurate if @i[location] is a variable, but if it is a call,
the subforms of the call are evaluated when the @tc[LOCATIVE]-expression
is evaluated, not when the contents of the locative are required.
For example,
@begin[ProgramExample]
(LOCATIVE (FOO (BAR BAZ)))
@ce[]
(LET ((TEMP1 FOO)
(TEMP2 (BAR BAZ)))
(OBJECT NIL
((CONTENTS SELF) (TEMP1 TEMP2))
(((SETTER CONTENTS) SELF VALUE) (SET (TEMP1 TEMP2) VALUE))
((LOCATIVE? SELF) T)))
@end[ProgramExample]
@EndDesc[LOCATIVE]
@info[NOTES="Settable operation"]
@desc[(CONTENTS @i[locative]) @yl[] @i[object]]
Dereferences (indirects through) the @i[locative].
@begin[ProgramExample]
(LSET Z (LIST 'A 'B)) @ev[] (A B)
(CONTENTS (LOCATIVE (CAR Z))) @ev[] A
(SET (CONTENTS (LOCATIVE (CAR Z))) 'C) @ev[] C
Z @ev[] (C B)
(CONTENTS (LOCATIVE @i[location])) @ce[] @i[location]
(SET (CONTENTS (LOCATIVE @i[location])) @i[value] @ce[] (SET @i[location] @i[value])
@end[ProgramExample]
@EndDesc[CONTENTS]
@info[NOTES="Type predicate operation"]
@desc[(LOCATIVE? @i[object]) @yl[] @i[boolean]]
Returns true if @i[object] is a locative.
@EndDesc[LOCATIVE?]
@section[Dynamic state]
@label[dynamic state section] @Comment{ref: control chapter.}
@index[dynamic state]
@AnEquivE[Tfn="BIND",Efn="SPECIAL"]
@AnEquivE[Tfn="BIND",Efn="LET"]
@info[NOTES="Special form"]
@desc[(BIND @i[specs] . @i[body]) @yl[] @i[value-of-body]]
@tc[BIND] implements @ix[dynamic binding]. Syntactically, it is similar
to @tc[LET], but semantically it is completely different. @tc[BIND]
operates by doing temporary assignments to locations, for example, to
bound variables. Unlike @tc[LET], it does not introduce a new lexical
binding contour.
Note that the use of the term @i[bind] in this context is
unrelated to its use elsewhere (for example, at the beginning of chapter
@ref[environments]).
Each @i[spec] should have the syntax
@begin[ProgramExample]
(@i[location] @i[value])
@end[ProgramExample]
The value in each @i[location] is obtained and saved.
Each @i[location] is assigned the @i[value], as with @tc[SET].
The @i[body] expressions are evaluated and the value of the last
is saved. The @i[locations] are then restored to their original
saved values. The @tc[BIND]-expression finally yields the saved value
of the @i[body].
@begin[ProgramExample]
(BIND ((@i[location] @i[value])) . @i[body])
@end[ProgramExample]
is therefore similar to
@begin[ProgramExample]
(LET ((SAVED-VALUE @i[location]))
(SET @i[location] @i[value])
(BLOCK0 (BLOCK . @i[body])
(SET @i[location] SAVED-VALUE)))
@end[ProgramExample]
or
@begin[ProgramExample]
(LET ((SAVED-VALUE @i[location]))
(SET @i[location] @i[value])
(UNWIND-PROTECT (BLOCK . @i[body])
(SET @i[location] SAVED-VALUE)))
@end[ProgramExample]
Examples:
@begin[ProgramExample]
(LSET A 1)
(DEFINE (F) (+ A 1))
(F) @ev[] 2
(LET ((A 10)) (F)) @ev[] 2
(BIND ((A 10)) (F)) @ev[] 11
(LSET X (LIST 1 2 3))
(BIND (((CAR X) 10))
(LSET Y (COPY-LIST X)))
X @ev[] (1 2 3)
Y @ev[] (10 2 3)
@end[ProgramExample]
The values in the @i[locations] are restored, even
if a throw out of @i[body] occurs (see @tc[CATCH], page @pageref[CATCH]).
For example:
@begin[TEG]
(LET ((A 10))
(CATCH EP (BIND ((A 20)) (EP NIL)))
A)
@ev[] 10
@end[TEG]
Any @i[location] in a @tc[BIND]-form which is a variable name
should name a variable which has been previously bound
using, for example, @tc[LSET] or @tc[LET].
@EndDesc[BIND]
@info[NOTES="Special form"]
@Desc[(UNWIND-PROTECT @i[form . unwind-forms]) @yl[] @i[value-of-form]]
@tc[UNWIND-PROTECT] behaves nearly the same as @tc[BLOCK0]:
the @i[form] is evaluated, and the value is saved; the @i[unwind-forms]
are evaluated; and the @tc[UNWIND-PROTECT]-expression yields the (saved)
value of @i[form]. However, unlike @tc[BLOCK0],
@tc[UNWIND-PROTECT] guarantees that
the @i[unwind-forms] will be evaluated,
even if a throw occurs
during the evaluation of @i[form].
In the following example, the motor will be stopped even if @tc[DRILL-HOLE]
attempts to throw out of the @tc[UNWIND-PROTECT].
@begin[ProgramExample]
(UNWIND-PROTECT (BLOCK (START-MOTOR)
(DRILL-HOLE))
(STOP-MOTOR))
@end[ProgramExample]
A throw (see page @pageref[CATCH]) out of the @tc[BLOCK] @dash[] for example,
as a result of calling @tc[DRILL-HOLE], will evaluate the exit form
@wt[(STOP-MOTOR)] before control finally returns to its corresponding
@tc[CATCH].
It is an error to throw out of the unwind forms of an @tc[UNWIND-PROTECT].
@EndDesc[UNWIND-PROTECT]
@dc{ Talk about dynamic state; @qu"soft" and @qu"hard" throws;
the difference between @tc[BIND] and @tc[UNWIND-PROTECT]; etc. }